﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Shapes;
using System.Windows.Threading;
using Lime49.UI;
using LockCrypt.DAL;
using LockCrypt.Core;
using System.Windows.Interop;

namespace LockCrypt {
    /// <summary>
    /// Window for managing templates.
    /// </summary>
    public partial class WinTemplates : Window {
        private BackgroundWorker _worker;
        /// <summary>
        /// Initializes a new <see cref="WinTemplates"/>.
        /// </summary>
        public WinTemplates() {
            InitializeComponent();
        }

        /// <summary>
        /// Fires the Refresh command to load available templates when the Window loads.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.RoutedEventArgs"/> instance containing the event data.</param>
        private void Window_Loaded(object sender, RoutedEventArgs e) {
            NavigationCommands.Refresh.Execute(null, this);
        }

        #region CRUD
        /// <summary>
        /// Loads available templates.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void LoadTemplates(object sender, ExecutedRoutedEventArgs e) {
            _worker = new BackgroundWorker();
            _worker.DoWork += (s, dwe) => {
                IList<ITemplate> baseTemplates = DalConfigurationManager.Provider.GetTemplates();
                IEnumerable<Template> templates = baseTemplates.OrderBy(t => t.Name).Select(t => new Template(t));
                dwe.Result = templates;
            };
            _worker.RunWorkerCompleted += (s, rwe) => {
                if(rwe.Error != null) {
                    DialogBox.ShowAlert(this, rwe.Error, I18nUtils.GetString("Errors", "Error"));
                } else if(rwe.Result is IEnumerable<Template>) {
                    IEnumerable<Template> templates = rwe.Result as IEnumerable<Template>;
                    SetRecordCount(templates.Count());
                    lstTemplates.IsEnabled = true;
                    int selectedIndex = lstTemplates.SelectedIndex;
                    lstTemplates.ItemsSource = templates;
                    if(selectedIndex >=0 && selectedIndex < lstTemplates.Items.Count) {
                        lstTemplates.SelectedIndex = selectedIndex;
                        var container = lstTemplates.ItemContainerGenerator.ContainerFromIndex(selectedIndex) as ListBoxItem;
                        container.Focus();
                        Console.WriteLine(lstTemplates.ItemContainerGenerator.ContainerFromIndex(selectedIndex).GetType());
                    }
                    lstTemplates.DisplayMemberPath = "Name";
                    CommandManager.InvalidateRequerySuggested();
                }
            };
            lstTemplates.IsEnabled = false;
            _worker.RunWorkerAsync();
        }

        /// <summary>
        /// Shows a dialog to add a new template.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void AddTemplate(object sender, ExecutedRoutedEventArgs e) {
            WinAddTemplate dlg = new WinAddTemplate() { Owner = this };
            if(dlg.ShowDialog() == true) {
                ITemplate template = dlg.SelectedTemplate;
                WaitForWorker();
                _worker = new BackgroundWorker();
                _worker.DoWork += (s, dwe) => DalConfigurationManager.Provider.AddTemplates(new[] { template }, null);
                _worker.RunWorkerCompleted += (s, rwe) => {
                    SetStatus(null);
                    if(rwe.Error != null) {
                        DialogBox.ShowAlert(this, rwe.Error.Message, I18nUtils.GetString("Errors", "ErrorSaving"));
                    } else {
                        if(rwe.Result != null) {// error log
                            DialogBox.ShowAlert(this, rwe.Result.ToString(), I18nUtils.GetString("Errors", "ErrorSaving"));
                        }
                        NavigationCommands.Refresh.Execute(null, this);
                    }
                    CommandManager.InvalidateRequerySuggested();
                };
                _worker.RunWorkerAsync();
            }
        }

        /// <summary>
        /// Shows the 'Edit Template' dialog.
        /// </summary>
        private void EditTemplate(object sender, ExecutedRoutedEventArgs e) {
            ITemplate template = e.Parameter as ITemplate;
            if(template == null)
                return;
            WinAddTemplate dlg = new WinAddTemplate(template.Clone()) { Owner = this };
            if(dlg.ShowDialog() == true) {
                ITemplate newTemplate = dlg.SelectedTemplate;
                WaitForWorker();
                _worker = new BackgroundWorker();
                _worker.DoWork += (s, dwe) => DalConfigurationManager.Provider.EditTemplate(newTemplate);
                _worker.RunWorkerCompleted += (s, rwe) => {
                    SetStatus(null);
                    if(rwe.Error != null) {
                        DialogBox.ShowAlert(this, rwe.Error.Message, I18nUtils.GetString("Errors", "ErrorSaving"));
                    } else {
                        NavigationCommands.Refresh.Execute(null, this);
                    }
                    CommandManager.InvalidateRequerySuggested();
                };
                _worker.RunWorkerAsync();
            }
        }

        /// <summary>
        /// Confirms deletion of a template.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void DeleteTemplate(object sender, ExecutedRoutedEventArgs e) {
            ITemplate template = (e.Parameter ?? lstTemplates.SelectedItem) as ITemplate;
            if(template == null)
                return;
            if(DialogBox.Show(this, I18nUtils.GetString("Strings", "DeleteTemplateDesc"), I18nUtils.GetString("Strings", "ConfirmDeletion"), DialogBox.DialogBoxType.YesNo, DialogBox.DialogBoxIcon.Question, DialogBoxButton.No) == DialogBoxButton.Yes) {
                WaitForWorker();
                _worker = new BackgroundWorker();
                _worker.DoWork += (s, dwe) => DalConfigurationManager.Provider.DeleteTemplate(template.ID);
                _worker.RunWorkerCompleted += (s, rwe) => {
                    SetStatus(null);
                    if(rwe.Error != null) {
                        DialogBox.ShowAlert(this, rwe.Error.Message, I18nUtils.GetString("Errors", "Error"));
                    } else {
                        NavigationCommands.Refresh.Execute(null, this);
                    }
                    CommandManager.InvalidateRequerySuggested();
                };
                SetStatus(string.Empty);
                _worker.RunWorkerAsync();
            }
        }

        /// <summary>
        /// Fires the properties command when an item is double clicked.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.Windows.Input.MouseButtonEventArgs"/> instance containing the event data.</param>
        private void lst_MouseDoubleClick(object sender, MouseButtonEventArgs e) {
            if(!(e.Source is ListBoxItem))
                return;
            ITemplate template = (e.Source as ListBoxItem).Content as ITemplate;
            if(template != null) {
                ApplicationCommands.Properties.Execute(template, this);
            }
        }
        #endregion

        /// <summary>
        /// Shows the help file.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.ExecutedRoutedEventArgs"/> instance containing the event data.</param>
        private void ShowHelp(object sender, ExecutedRoutedEventArgs e) {
            WPFUtils.OpenHelp("Templates.html");
        }

        /// <summary>
        /// Always returns true.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
        private void CanAlwaysExecute(object sender, CanExecuteRoutedEventArgs e) {
            e.CanExecute = true;
        }

        /// <summary>
        /// Determines whether an item is selected.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
        private void IsItemSelected(object sender, CanExecuteRoutedEventArgs e) {
            e.CanExecute = IsLoaded && lstTemplates.SelectedItem != null && (_worker == null || !_worker.IsBusy);
        }

        /// <summary>
        /// Determines whether the BackgroundWorker is busy.
        /// </summary>
        /// <param name="sender">The sender.</param>
        /// <param name="e">The <see cref="System.Windows.Input.CanExecuteRoutedEventArgs"/> instance containing the event data.</param>
        private void IsWorkerBusy(object sender, CanExecuteRoutedEventArgs e) {
            e.CanExecute = IsLoaded && (_worker == null || !_worker.IsBusy);
        }

        /// <summary>
        /// Waits for the BackgroundWorker to complete before returning.
        /// </summary>
        private void WaitForWorker() {
            if(_worker != null && _worker.IsBusy) {
                while(_worker.IsBusy) {
                    Dispatcher.Invoke(DispatcherPriority.Background, new ThreadStart(delegate() { }));
                }
            }
        }

        /// <summary>
        /// Sets the text on the status message (null hides the statusbar and label).
        /// </summary>
        /// <param name="message">The message.</param>
        private void SetStatus(string message) {
            if(message == null) {
                prgStatus.Visibility = Visibility.Collapsed;
                lblStatus.Visibility = Visibility.Collapsed;
            } else {
                prgStatus.Visibility = Visibility.Visible;
                lblStatus.Visibility = Visibility.Visible;
                lblStatus.Text = message;
            }
        }

        /// <summary>
        /// Sets the text for the number of items label to the left of the status bar.
        /// </summary>
        /// <param name="count">The number of items. Less than zero hides the label.</param>
        private void SetRecordCount(int count) {
            if(count >= 0) {
                lblRecordCount.Text = I18nUtils.GetString("Strings", "NumTemplatesFmt", count.ToString());
                lblRecordCount.Visibility = Visibility.Visible;
            } else {
                lblRecordCount.Visibility = Visibility.Collapsed;
            }
        }
    }
}
